package com.zyj.websocket;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * https://www.oracle.com/technical-resources/articles/java/jsr356.html
 * 基于jsr356的websocket实现
 */
@Component
@ServerEndpoint("/zyj/abc/{num}")
//@ServerEndpoint(value = "/zyj/abc/{num}",configurator = SpringConfigurator.class)
public class WebSocketServer {

    /**
     * 虽然 WebSocketServer 是一个Component
     * 但是每次回调的onOpen,onMessage 都会新new一个 WebSocketServer 进行处理, 而这个对WebSocketServer对象并不是在spring的管理之中
     */
//    @Autowired //autowired 不起作用, 因为每个连接都会创建一个 WebSocketServer 对象, 不在spring管理之中
//    private WebSocketConfig webSocketConfig;

    // session集合,存放对应的session
    private static CopyOnWriteArraySet<Session> sessionSet = new CopyOnWriteArraySet<>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value = "num") Integer num) {
//        System.out.println(webSocketConfig); //null
//        throw new RuntimeException("999");
        System.out.println("onOpen; this = " + this);
        System.out.println("onOpen; num = " + num);
        System.out.println("onOpen; session = " + session);
        //ws://172.19.0.80:8080/zyj/abc/1?a=123
        System.out.println("onOpen; session queryString = " + session.getQueryString());
        System.out.println("onOpen; thread name = " + Thread.currentThread().getName());
        sessionSet.add(session);
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        System.out.println("onError; session = " + session);
        System.out.println("onError; throwable = " + throwable);
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("onClose; this = " + this);
        //销毁spring容器的时候, 自动会close
        System.out.println("onClose; session = " + session);
        sessionSet.remove(session);
    }

    @OnMessage(maxMessageSize = 1024 * 1024 * 64) //单个消息最大64MB
    public void onMessage(Session session, String message) throws IOException {
        System.out.println("onMessage; this = " + this);
        System.out.println("onMessage; session = " + session);
//        System.out.println("onMessage; message size = " + message);
        System.out.println("onMessage; message = " + message);
        System.out.println("onMessage; thread name = " + Thread.currentThread().getName());
//        session.getBasicRemote().sendText(message);//echo
//        session.getAsyncRemote().sendText(message);//并发的发送数据, 会导致报错, TEXT_FULL_WRITING; java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
//        server.tomcat.max-connections=10000
    }
    //ws://172.19.0.80:8080/zyj/abc/123

    public static void broadcast(String msg) throws IOException {
        for (Session session : sessionSet) {
            synchronized (session) {
                //给同一个session发消息, 必须是顺序的, 单线程操作
                session.getBasicRemote().sendText(msg);
            }
        }
    }

    public static void broadcast2(String msg) throws IOException {
        for (Session session : sessionSet) {
            //多线程并发发送会报错
            //Exception in thread "pool-1-thread-9638" java.lang.IllegalStateException: The remote endpoint was in state [TEXT_FULL_WRITING] which is an invalid state for called method
            session.getBasicRemote().sendText(msg, true);
        }
    }

}
